home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / xc.cq / xc.c
Text File  |  1984-04-16  |  33KB  |  1,084 lines

  1. /***********************************************************/
  2. /*    XC.C                           */
  3. /*                               */
  4. /*    Last modified:    22:50    20 May    84    RSW       */
  5. /*                               */
  6. /*    Abstract:                           */
  7. /*                               */
  8. /*    'XC' is a    cross-reference    utility    for 'C'    programs.  */
  9. /*    Its has the ability to handle nested include files   */
  10. /*    to a depth of 8 levels and properly processes nested */
  11. /*    comments as supported by BDS C. Option flags support */
  12. /*    the following features:                   */
  13. /*                               */
  14. /*    -    Routing    of list    output to disk               */
  15. /*    -    Cross-referencing of reserved words           */
  16. /*    -    Processing of nested include files           */
  17. /*    -    Generation of listing only               */
  18. /*                               */
  19. /*    Usage: xc    <filename> <flag(s)>               */
  20. /*                               */
  21. /*    Flags: -i           = Enable file inclusion       */
  22. /*         -l           = Generate listing only       */
  23. /*         -c           = Compressed    print listing       */
  24. /*         -r           = Cross-ref reserved    words       */
  25. /*         -o    <filename> = Write output to named file       */
  26. /*                               */
  27. /*************************************************************************/
  28. /*  5-20-84  Changes            R.S. White             */
  29. /*     - made compilation for Lattice C    ver 2.0    or Computer Innovations     */
  30. /*          CI-C86 optional by setting #define labels    accordingly.     */
  31. /*     - made printer selection    for compressed print selectable    by     */
  32. /*          setting #define labels accordingly.  Added Epson FX and     */
  33. /*          Gemini-10X printer control strings.             */
  34. /*************************************************************************/
  35. /*  1-01-84  Enhancements        S.R. Jacobson             */
  36. /*     - changed -e option to -c option    and added two strings:         */
  37. /*          cprint_hdr sets the printer to compressed    print mode     */
  38. /*          cprint_trlr resets the printer to    "normal" mode         */
  39. /*       This    makes it easier    for non-epson printer users         */
  40. /*     -  removed all the BDS C    comments (this makes it    easier to modify */
  41. /*          in the future.                         */
  42. /*     -  changed name of the utility to the "print" utility         */
  43. /*     -  if the -i flag is not    used, the second line number will not     */
  44. /*          appear.                             */
  45. /*     -  if a form feed is detected in    the source file, a new page is     */
  46. /*          started.    This is    useful for structuring the source     */
  47. /*          code by placing each major section on a separate page.     */
  48. /*          You do this by embedding a form feed (control L) in a     */
  49. /*          comment.    The text following the form feed will be placed     */
  50. /*          on the top of the    new page.                 */
  51. /*     -  tab characters in the    file are expanded to every 8 positions.     */
  52. /*          This may be changed by changing the TABCNT define.     */
  53. /*     -  added    the date and time to the printed output. (C-86 only)     */
  54. /*     -  fixed    error in hashing algorithm.                 */
  55. /*     -  control characters (other than \n, \f, or \t)    are stripped     */
  56. /*          from the input stream (converted to blanks).  This     */
  57. /*          prevents extraneous control chars    from interfering with     */
  58. /*          operation    of xc.                         */
  59. /*     -  cleaned up the structuring of    a number of routines.         */
  60. /*     -  added    the file latest    update date and    time to    the printed     */
  61. /*          output. ***DOS 2.0 ONLY ***                 */
  62. /*************************************************************************/
  63. /*   9-26-83   Microsoft C 1.04     Conversion    WHR             */
  64. /*     -  \t between line numbers and text to fix indenting problem.     */
  65. /*     -  added    option -e for output to    Epson in condensed print.     */
  66. /*     -  toupper() and    isupper() are macros, not functions.         */
  67. /*     -  eliminate side effect    in toupper(*++arg) in main().         */
  68. /*     -  change alloc() to malloc().                     */
  69. /*     -  add #define NAMES that are not in stdio.h             */
  70. /*     -  MS-C requires    () in statement    A?(c=B):(c=C)    error or not??     */
  71. /*                                     */
  72. /*   4-30-83   Computer    Innovations C-86 1.31 Conversion    WHR         */
  73. /*     -  #include filename changed to allow a disk drive prefix, D:     */
  74. /*     -  convert if(fprintf(...) == ERROR) lst_err(); to fprintf(..);     */
  75. /*     -  convert if(fopen(...)    == ERROR) statements to    == NUL0.     */
  76. /*     -  C86 requires () in statement A?(c=B):(c=C)    error or not??     */
  77. /*     -  remove getc()    == ERROR check in fil_chr().             */
  78. /*     -  convert file conventions from    BDS C to C-86.             */
  79. /*     -  comment out BDS unique statements, mark revised statements.     */
  80. /*      keep all BDS statements to document conversion effort.     */
  81. /*                                     */
  82. /**  4-19-83   BDS C Version file XC.CQ    copied from Laurel RCPM       WHR     */
  83. /*************************************************************************/
  84. /*   **    Original Version: **                   */
  85. /*                               */
  86. /*    Version 1.0   January, 1982               */
  87. /*                               */
  88. /*    Copyright    (c) 1982 by Philip N. Hisley           */
  89. /*                               */
  90. /*    Released for non-commercial distribution only       */
  91. /*                               */
  92. /*    Please report bugs/fixes/enhancements to:           */
  93. /*                               */
  94. /*          Philip N.    Hisley                   */
  95. /*          548H Jamestown Court               */
  96. /*          Edgewood,    Maryland 21040               */
  97. /*          (301) 679-4606                   */
  98. /*          Net Addr:    PNH@MIT-AI               */
  99. /*                               */
  100. /*                               */
  101. /***********************************************************/
  102.  
  103. /*   DEFINITIONS AND VARIABLES    */                /*SRJ*/
  104.  
  105. #include <stdio.h>                        /* WHR */
  106.  
  107. #define    LATTICE    1    /* set to use Lattice C    ver 2.0    compiler */ /*RSW*/
  108. #define    CIC86    0    /* disable Computer Innovations    compiler */ /*RSW*/
  109.  
  110. #define    GEMIN10X 0    /* enable Gemini-10X printer codes    */  /*RSW*/
  111. #define    EPSONMX     0                            /*RSW*/
  112. #define    EPSONFX     0                            /*RSW*/
  113. #define    IDSPRISM 1                            /*RSW*/
  114.  
  115. #if LATTICE
  116. #include <ctype.h>    /* Lattice C ver 2.0 - macros */        /*RSW*/
  117. #endif
  118.  
  119. #define     TABCNT        8        /* expand tabs to every    8 characters */     /*SRJ*/
  120. #define     NUL0        0
  121. #define     FALSE        0                          /* WHR */
  122. #define     TRUE        1                          /* WHR */
  123. #define     CPMEOF      0x1A              /* end of    file */          /* WHR */
  124. #define     ERROR      (-1)                          /* WHR */
  125.  
  126. #define     MAX_REF    5        /* maximum refs    per ref-block */
  127.  
  128. #define     MAX_LEN 39  /*    maximum    identifier length -n opt Lattice C */ /*RSW*/
  129. #define     MAX_WRD   749        /* maximum number of identifiers */
  130. #define     MX_ALPHA  53        /* maximum alpha chain heads */          /*RSW*/
  131. #define     REFS_LIN  8        /* maximum refs    per line */          /*RSW*/
  132. #define     LINE_PAG  60    /* note    Lattice    C gets confused    if -n  */     /*RSW*/
  133.             /* option is used and #define labels   */
  134.             /* are longer than 8 characters           */
  135.  
  136. struct    id_blk {
  137.          char  id_name[MAX_LEN];
  138.          struct    id_blk *alpha_lnk;
  139.          struct    rf_blk *top_lnk;
  140.          struct    rf_blk *lst_lnk;
  141.            } oneid;
  142.  
  143. struct    rf_blk {
  144.          int  ref_item[MAX_REF];
  145.          int  ref_cnt;
  146.            } onerf;
  147.  
  148. struct id_blk *id_vector[MAX_WRD];
  149.  
  150. struct alpha_hdr { struct id_blk *alpha_top;
  151.            struct id_blk *alpha_lst;
  152.          };
  153.  
  154. struct alpha_hdr alpha_vector[MX_ALPHA];
  155.  
  156. struct    regval    {
  157.         unsigned int ax,bx,cx,dx,si,di,ds,es;
  158.         } reg; /*structure for sysint*/               /*SRJ*/
  159.  
  160. struct    regv    {
  161.         unsigned int csx,ssx,dsx,esx;
  162.         } regx;       /* structure    for segread*/           /*SRJ*/
  163.  
  164.  
  165. int    y,mo,d;            /* year,month and day for date */  /*SRJ*/
  166. int    h,mi,s;            /* hours, minutes, seconds for time */ /*SRJ*/
  167.  
  168. char    *months[]=        /* month names for date    */        /*SRJ*/
  169.         {"bad month","January","February","March","April","May","June",
  170.         "July","August","September","October","November","December"};
  171.  
  172. int    ln_chr=0;        /* # of    characters in the line (for tab)SRJ*/
  173.  
  174. unsigned int    handle;            /* dos file handle */        /*SRJ*/
  175. unsigned int file_d,file_mo,file_y,file_h,file_mi; /* file m/d/y and h:m  SRJ*/
  176.  
  177. FILE    *tb;            /* temp    fd */                /*SRJ*/
  178.  
  179.  
  180. int    linum;        /* line    number */
  181. int    edtnum;        /* edit    line number */
  182. int    fil_cnt;    /* active file index */
  183. int    wrd_cnt;    /* token count */
  184. int    pagno;        /* page    number */
  185. int    id_cnt;        /* number of unique identifiers    */
  186. int    rhsh_cnt;    /* number of conflict hits */
  187. int    filevl;        /* file    level  */
  188. int    paglin;        /* page    line counter */
  189. int    prt_ref;
  190. char    act_fil[MAX_LEN];
  191. char    lst_fil[MAX_LEN];
  192. char    gbl_fil[MAX_LEN];
  193. FILE   *l_buffer;                         /*      WHR */
  194. int    i_flg,o_flg,r_flg,l_flg;
  195. int    debug;
  196. int    c_flg;                             /*    WHR */
  197.  
  198.  
  199. /* The following two strings are the compressed    print header and the
  200. trailer    that returns the printer to the    normal mode.  These must
  201. be changed for each printer.  They are currently set up    for the      */
  202.  
  203. #if GEMIN10X                                /*RSW*/
  204. char cprint_hdr[]="\x1bB\3\1bQ\x84"; /*    header string for Gemini-10X */
  205. char cprint_trlr[]="\x1bB\2"; /* ELITE mode trailer string for Gemini-10X */
  206. #endif
  207.  
  208. #if IDSPRISM                                /*RSW*/
  209. char    cprint_hdr[] = "\037";  /* header string for Prism 80 */
  210. char    cprint_trlr[] =    "\035";    /* trailer string for Prism 80 */
  211. #endif
  212.  
  213. #if EPSONMX                                /*RSW*/
  214. char    cprint_hdr[] = "\x1b\x40\x0F\x1BQ\x84";                /*WHR*/
  215. char    cprint_trlr[] =    "\x1b\x40";    /* trailer string for Epson MX */
  216. #endif
  217.  
  218. #if EPSONFX                                /*RSW*/
  219. char cprint_hdr[]="\x1b!\4\x1bQ\x84"; /* header    string for Epson FX */    /*WHR*/
  220. char cprint_trlr[]="\x1b!\1"; /*ELITE mode trailer string for Epson FX*/ /*RSW*/
  221. #endif
  222.  
  223.  
  224. /* end of printer strings */
  225. /*   MAIN PROGRAM    */                    /*SRJ*/
  226.  
  227.  
  228. main(argc,argv)
  229.      int     argc;
  230.      char    **argv;
  231.  
  232.      {char  *arg;
  233.      char *strcpy();
  234. /*** int  toupper();   ***/             /*    Microsoft C   macro */
  235.      char cc;                     /*    Microsoft C */
  236.  
  237. /*  The    the parameters    */
  238.  
  239.      if    (argc <    2) use_err();
  240.      i_flg=r_flg=o_flg=l_flg=FALSE;
  241.      debug = FALSE;
  242.      strcpy(gbl_fil,*++argv);
  243.      --argc;
  244.      if(gbl_fil[0] == '-')
  245.       use_err();
  246.      while(--argc != 0)
  247.      {      if(*(arg=*++argv) == '-')
  248.     /*****{    switch( toupper(*++arg) )     *** side effect in    Microsoft C */
  249.       {    switch( cc=*++arg, toupper(cc) )             /*    Microsoft C */
  250.            {   case    'I':  i_flg++;
  251.                   break;
  252.            case    'R':  r_flg++;
  253.                   break;
  254.            case    'L':  l_flg++;
  255.                   break;
  256.            case    'O': {o_flg++;
  257.                   if(--argc    == 0) use_err();
  258.                   strcpy(lst_fil,*++argv);
  259.                   if(lst_fil[0] == '-') use_err();
  260.                   if(debug)    printf("lst_fil=>%s<",lst_fil);
  261.                   break;
  262.                  }
  263.            case    'D':  debug++;
  264.                   break;
  265.            case    'C':  c_flg++;            /* SRJ */ /* WHR */
  266.                   o_flg++;
  267.                   strcpy(lst_fil,"PRN:");    /* SRJ */
  268.                   break;
  269.            default:   use_err();
  270.            }
  271.       }
  272.      else use_err();
  273.      }
  274.      if(debug) printf("\ni_flg=%d, r_flg=%d, l_flg=%d",    i_flg,r_flg,l_flg);
  275.      if(debug) printf("\no_flg=%d, debug=%d", o_flg,debug);
  276.      if    (o_flg)
  277.       {if (    (l_buffer = fopen(lst_fil,"w"))    == NUL0)   /***    output file ***/
  278.           {printf("ERROR: Unable to create list file - %s\n",lst_fil);
  279.            exit(0);
  280.           }
  281.       printf("\nXC ....... 'C' Print Utility  v1.1\n");        /*RSW*/
  282.       if (c_flg) fprintf(l_buffer,"%s",cprint_hdr);
  283.       }
  284.       else                                /*SRJ*/
  285.       l_buffer=stdout;    /* if no output    file, use stdout */    /*SRJ*/
  286.  
  287. /* THE FOLLOWING CODE GETS THE DATE AND    THE TIME FROM DOS.  IT USES THE
  288. ROUTINES SYSINT    AND SEGREAD PROVIDED BY    THE CI C-86 LIBRARY.  THIS IS CI C-86
  289. DEPENDENT CODE AND MUST    BE CHANGED FOR OTHER COMPILERS         */    /*SRJ*/
  290. /* added Lattice C ver 2.00 int86 calls    to do the same */        /*RSW*/
  291.  
  292. segread(®x);        /* get the segment registers */            /*SRJ*/
  293. reg.ds=regx.dsx;    /* save    the ds in the sysint data */        /*SRJ*/
  294. reg.es=regx.esx;    /* save    the es in the sysint data */        /*SRJ*/
  295.  
  296. /* get the date    */                            /*SRJ*/
  297. reg.ax=0x2A00;            /* date    request    code */            /*SRJ*/
  298.  
  299. #if CIC86
  300. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  301. #endif
  302.  
  303. #if LATTICE
  304. int86(0x21,®,®);        /* Lattice C ver 2.0 interupt */    /*RSW*/
  305. #endif
  306.  
  307. y=reg.cx;            /* store year */            /*SRJ*/
  308. mo=reg.dx>>8;            /* store month */            /*SRJ*/
  309. d=reg.dx & 0xFF;        /* get the day */            /*SRJ*/
  310.  
  311. /* get the time    */                            /*SRJ*/
  312. reg.ax=0x2C00;            /* time    request    code */            /*SRJ*/
  313.  
  314. #if CIC86
  315. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  316. #endif
  317.  
  318. #if LATTICE
  319. int86(0x21,®,®);        /* Lattice C ver 2.0 interupt */    /*RSW*/
  320. #endif
  321.  
  322. h=reg.cx>>8;            /* get hours */                /*SRJ*/
  323. mi=reg.cx & 0xFF;        /* get minutes */            /*SRJ*/
  324. s=reg.dx>>8;            /* get seconds */            /*SRJ*/
  325.  
  326. /* NOW WE GET THE FILE LATEST UPDATE DATE AND TIME */
  327.  
  328. /* first try to    open the file */
  329.  
  330. if ((tb    = fopen(gbl_fil,"r")) == NUL0)    /*open the input file */    /*SRJ*/
  331.     {printf("\nERROR: Unable to open input file: %s\n",gbl_fil);    /*SRJ*/
  332.     exit(10);                            /*SRJ*/
  333.     }
  334. fclose(tb);            /* close the file */            /*SRJ*/
  335.  
  336. /* note-we have    no way to get an error indication back from the    dos call
  337. below (file open),  so we have to open it to see if it is there    before
  338. we can use the proceedure below    */                    /*SRJ*/
  339.  
  340. /* now get the file date and time */                    /*SRJ*/
  341.  
  342. /* open    the file   -  we assume    the file exists    */            /*SRJ*/
  343. reg.ax=0x3D00;            /* open    request    code */            /*SRJ*/
  344.  
  345. /* reg.dx=gbl_fil;   */        /* address of file name    */        /*SRJ*/
  346. reg.dx = &gbl_fil;        /* address of file name    */        /*RSW*/
  347.  
  348. #if CIC86
  349. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  350. #endif
  351.  
  352. #if LATTICE
  353. int86(0x21,®,®);        /* Lattice C ver 2.0 interupt */    /*RSW*/
  354. #endif
  355.  
  356. handle=reg.ax;            /* store file handle */            /*SRJ*/
  357.  
  358. /* get the date    and time */                        /*SRJ*/
  359. reg.ax=0x5700;            /* time    request    code */            /*SRJ*/
  360. reg.bx=handle;            /* file    handle in bx */            /*SRJ*/
  361.  
  362. #if CIC86
  363. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  364. #endif
  365.  
  366. #if LATTICE
  367. int86(0x21,®,®);        /* Lattice C ver 2.0 interupt */    /*RSW*/
  368. #endif
  369.  
  370.  
  371. /* unpack the file time    */                        /*SRJ*/
  372. file_h=(reg.cx >> 11) &    0x1F;        /* get hours */            /*SRJ*/
  373. file_mi=(reg.cx    >> 5) &    0x3f;        /* get minutes */        /*SRJ*/
  374.  
  375. /* unpack the file date    */                        /*SRJ*/
  376. file_d=reg.dx &    0x1F;            /* get the day */        /*SRJ*/
  377. file_mo= (reg.dx >> 5) & 0x0F;        /* get the month */        /*SRJ*/
  378.  
  379. file_y=( (reg.dx >> 9) & 0x7F )+80;    /* get the month */        /*SRJ*/
  380.  
  381. /* close the file */                            /*SRJ*/
  382.  
  383. reg.bx=handle;                                /*SRJ*/
  384. reg.ax=0x3D00;                                /*SRJ*/
  385.  
  386. #if CIC86
  387. sysint(0x21,®,®);        /* DOS interrupt */            /*SRJ*/
  388. #endif
  389.  
  390. #if LATTICE
  391. int86(0x21,®,®);        /* Lattice C ver 2.0 interupt */    /*RSW*/
  392. #endif
  393.  
  394.  
  395.  
  396. /* END OF compiler DEPENDENT CODE  */                    /*RSW*/
  397.  
  398.  
  399.      prt_ref = FALSE;
  400.      for(linum=0;linum < MAX_WRD;linum++)
  401.       id_vector[linum] = NUL0;
  402.  
  403.      for(linum=0;linum < MX_ALPHA;linum++)
  404.       alpha_vector[linum].alpha_top    =
  405.            alpha_vector[linum].alpha_lst = NUL0;
  406.  
  407.      fil_cnt = wrd_cnt = linum = 0;
  408.      filevl=paglin=pagno=edtnum=0;
  409.      id_cnt=rhsh_cnt=0;
  410.      proc_file(gbl_fil);
  411.      if(!l_flg)
  412.      {prnt_tbl();
  413.      printf("\nAllowable Symbols: %d\n",MAX_WRD);
  414.      printf("Unique    Symbols: %d\n",id_cnt);
  415.      }
  416.      if(o_flg)
  417.       {nl();
  418.       fprintf(l_buffer,"\nAllowable Symbols: %d\n",MAX_WRD);   /* WHR */
  419.       fprintf(l_buffer,"Unique    Symbols: %d\n",id_cnt);       /* WHR */
  420.       fprintf(l_buffer,"\f%c",CPMEOF);            /* WHR */
  421.       fprintf(l_buffer,"%s",cprint_trlr); /* output    trailer    */ /* SRJ */
  422.       fflush(l_buffer);
  423.       fclose(l_buffer);
  424.       }
  425. }
  426. /*    ERROR MESSAGE PRINT ROUTINES */                /*SRJ*/
  427.  
  428. lst_err()
  429.  
  430. {printf("\nERROR: Write error on list output file - %s\n",lst_fil);
  431. exit(0);
  432. }
  433.  
  434.  
  435. use_err()
  436.  
  437. {printf("\nERROR: Invalid parameter specification\n\n");
  438. printf("Usage: xc <filename> <flag(s)>\n\n");
  439. printf("Flags: -i             = Enable file inclusion\n");
  440. printf("       -l             = Generate listing only\n");
  441. printf("       -c             = Compressed print option\n");  /*SRJ*/
  442. printf("       -r             = Cross-reference reserved words\n");
  443. printf("       -o <filename>  = Write output to named file\n");
  444. exit(0);
  445. }
  446.  
  447. /*    PROCESS THE FILE    */                    /*SRJ*/
  448.  
  449. proc_file(filnam)
  450.  
  451. char    *filnam;
  452.  
  453. {FILE  *buffer;       /* allocated    buffer pointer */        /* WHR */
  454. char  token[MAX_LEN]; /* token buffer */
  455. int   eof_flg;       /* end-of-file indicator */
  456. int   tok_len;       /* token length */
  457. int   incnum;       /* included line number */
  458. char *strcpy();
  459.  
  460. strcpy(act_fil,filnam);
  461. if ((buffer = fopen(filnam,"r")) == NUL0)  /***    input file ***/    /* WHR */
  462.     {printf("\nERROR: Unable to open input file: %s\n",filnam);
  463.     exit(0);
  464.     }
  465. if(filevl++ == 0)
  466.     {prt_hdr();
  467.     nl();
  468.     }
  469. eof_flg    = FALSE;
  470.  
  471. do
  472.     {if(get_token(buffer,token,&tok_len,&eof_flg,0))
  473.         {if (debug) printf("token: %s   length: %d\n",token,tok_len);
  474.         if (chk_token(token))
  475.  
  476.              /*    #include processing changed to accept drive:   WHR */
  477.             {if (strcmp(token,"#include") == 0)
  478.                 {if (get_token(buffer,token,&tok_len,&eof_flg,1))
  479.                     {if (debug) printf("**token: %s   length: %d\n",
  480.                           token,tok_len);
  481.                     if (!i_flg)
  482.                         continue;
  483.                       else
  484.                         {incnum=edtnum;
  485.                         edtnum=0;
  486.                         nl();
  487.                         proc_file(token);
  488.                         edtnum=incnum;
  489.                         strcpy(act_fil,filnam);
  490.                         continue;
  491.                         }
  492.                     }
  493.                 }
  494.             put_token(token,linum);
  495.             }
  496.         }
  497.     }
  498. while (!eof_flg);
  499.  
  500. filevl -= 1;
  501. fclose(buffer);
  502. return;
  503. }
  504. /*    GET A TOKEN    */                        /*SRJ*/
  505.  
  506. get_token(g_buffer,g_token,g_toklen,g_eoflg,g_flg)
  507.  
  508. FILE    *g_buffer;
  509. char    *g_token;
  510. int    *g_toklen;
  511. int    *g_eoflg;
  512. int    g_flg;
  513.  
  514. /*
  515. *     'getoken' returns the next valid identifier or
  516. *     reserved word from a given file along with the
  517. *     character length of the token and an end-of-file
  518. *     indicator
  519. *
  520. */
  521.  
  522. {
  523.      int     c;
  524.      char    *h_token;
  525.      char    tmpchr;
  526.      char    tmpchr2;              /* WHR fix for B:filename.ext */
  527.  
  528.      h_token = g_token;
  529.  
  530.  gtk:                   /* top of loop, get new token */
  531.      *g_toklen = 0;
  532.      g_token = h_token;
  533.  
  534.     /*
  535.      *    Scan and discard any characters    until an alphabetic or
  536.      *    '_' (underscore) character is encountered or an    end-of-file
  537.      *    condition occurs
  538.      */
  539.  
  540.      while(  (!isalpha(*g_token    = rdchr(g_buffer,g_eoflg,g_flg)))
  541.          &&     !*g_eoflg    &&  *g_token !=    '_'
  542.          &&    *g_token != '0'    &&  *g_token !=    '#' );
  543.      if(*g_eoflg) return(FALSE);
  544.  
  545.      *g_toklen += 1;
  546.  
  547.     /*
  548.      *     Scan and collect identified alpanumeric token until
  549.      *     a non-alphanumeric character is encountered or    and
  550.      *     end-of-file condition occurs
  551.      */
  552.  
  553.      if(g_flg) {
  554.       tmpchr  = '.';
  555.       tmpchr2 = ':';           /* WHR fix for B:filename.ext */
  556.      }
  557.      else {
  558.       tmpchr  = '_';
  559.       tmpchr2 = '_';           /* WHR fix for B:filename.ext */
  560.      }
  561.      while( (isalpha(c=rdchr(g_buffer,g_eoflg,g_flg)) ||
  562.         isdigit(c) || c == '_' || c    == tmpchr || c == tmpchr2)
  563.         && !*g_eoflg)           /* WHR fix for B:filename.ext */
  564.      {      if(*g_toklen < MAX_LEN)
  565.       {    *++g_token = c;
  566.            *g_toklen += 1;
  567.       }
  568.      }
  569.  
  570.  
  571.     /*
  572.      *        Check to see if a numeric hex or octal constant has
  573.      *        been encountered ... if so dump it and try again
  574.      */
  575.  
  576.  
  577.      if    (*h_token == '0') goto gtk;
  578.  
  579.  
  580.     /*
  581.      *        Tack a NUL0    character onto the end of the token
  582.      */
  583.  
  584.      *++g_token    = NUL0;
  585.  
  586.     /*
  587.      *        Screen out all #token strings except #include
  588.      */
  589.  
  590.      if    (*h_token == '#' && strcmp(h_token,"#include"))    goto gtk;
  591.  
  592.      return (TRUE);
  593. }
  594. /*   READ A CHARACTER FROM THE FILE AND    PROCESS    IT */        /*SRJ*/
  595.  
  596.  
  597. rdchr(r_buffer,r_eoflg,rd_flg)
  598.      int     *r_eoflg;
  599.      FILE    *r_buffer;
  600.      int     rd_flg;
  601.  
  602. /*
  603.     'rdchr'    returns    the next valid character in a file
  604.     and an end-of-file indicator. A    valid character    is
  605.     defined    as any which does not appear in    either a
  606.     commented or a quoted string ... 'rdchr' will correctly
  607.     handle comment tokens which appear within a quoted
  608.     string
  609. */
  610.  
  611. {
  612.      int     c;
  613.      int     q_flg;         /*    double quoted string flag */
  614.      int     q1_flg;         /*    single quoted string flag */
  615.      int     cs_flg;         /*    comment    start flag */
  616.      int     ce_flg;         /*    comment    end flag */
  617.      int     c_cnt;         /*    comment    nesting    level */
  618.      int     t_flg;         /*    transparency flag */
  619.  
  620.      q_flg = FALSE;
  621.      q1_flg = FALSE;
  622.      cs_flg = FALSE;
  623.      ce_flg = FALSE;
  624.      t_flg = FALSE;
  625.      c_cnt  = 0;
  626.  
  627. rch:
  628.  
  629.  
  630.     /*
  631.      *     Fetch character from file
  632.      */
  633.  
  634.      c = fil_chr(r_buffer,r_eoflg) & 0x7F;    /* read    only 7 bit ascii */ /*SRJ*/
  635.  
  636.      if    (*r_eoflg) return(c);    /* EOF encountered */
  637.  
  638.      switch(c)            /* test    the returned character */   /*SRJ*/
  639.     {case '\n':        /* carriage return */            /*SRJ*/
  640.         nl();        /* output new line and line numbers */ /*SRJ*/
  641.         ln_chr=0;    /* set to first    char in    line */        /*SRJ*/
  642.         c=' ';        /* return a space */            /*SRJ*/
  643.         break;
  644.  
  645.     case '\f':        /* form    feed */                /*SRJ*/
  646.         prt_hdr();    /* output header and start new page*/ /*SRJ*/
  647.         fprintf(l_buffer,"     "); /* space over line #s */   /*SRJ*/
  648.         ln_chr=0;    /* set to first    char in    line */        /*SRJ*/
  649.         c=' ';        /* set char to blank */            /*SRJ*/
  650.         break;
  651.  
  652.     case '\t':        /* tab character */        /*SRJ*/
  653.         do        /* expand the tabs */        /*SRJ*/
  654.             fputc(' ',l_buffer);            /*SRJ*/
  655.         while( (++ln_chr % TABCNT) != 0);        /*SRJ*/
  656.         c=' ';        /* set char to blank */            /*SRJ*/
  657.         break;
  658.  
  659.  
  660.     default:
  661.         ln_chr++;        /* move    to next    char pos */  /*SRJ*/
  662.         if( iscntrl(c) )    /* insure no control chars */ /*SRJ*/
  663.             c=' ';
  664.         fputc(c,l_buffer);    /* and output next char    */   /*SRJ*/
  665.     }
  666.  
  667.      if    (rd_flg) return(c);
  668.  
  669.      if    (t_flg)    {
  670.       t_flg    = !t_flg;
  671.       goto rch;
  672.      }
  673.  
  674.      if    (c == '\\') {
  675.       t_flg    = TRUE;
  676.       goto rch;
  677.      }
  678.     /*
  679.     If the character is not    part of    a quoted string
  680.     check for and process commented    strings...
  681.     nested comments    are handled correctly but unbalanced
  682.     comments are not ... the assumption is made that
  683.     the syntax of the program being    xref'd is correct
  684.     */
  685.  
  686.      if    (!q_flg     &&  !q1_flg) {
  687.       if (c    == '*'    &&  c_cnt  &&  !cs_flg)    {
  688.            ce_flg =    TRUE;
  689.            goto rch;
  690.       }
  691.       if (c    == '/'    &&  ce_flg) {
  692.            c_cnt -=    1;
  693.            ce_flg =    FALSE;
  694.            goto rch;
  695.       }
  696.       ce_flg = FALSE;
  697.       if (c    == '/')    {
  698.            cs_flg =    TRUE;
  699.            goto rch;
  700.       }
  701.       if (c    == '*'    &&  cs_flg) {
  702.            c_cnt +=    1;
  703.            cs_flg =    FALSE;
  704.            goto rch;
  705.       }
  706.       cs_flg = FALSE;
  707.  
  708.       if (c_cnt) goto rch;
  709.      }
  710.  
  711.     /*
  712.     Check for and process quoted strings
  713.     */
  714.  
  715.      if    ( c == '"'  &&  !q1_flg) {      /* toggle quote flag */
  716.       q_flg    =  !q_flg;
  717.       if(debug) printf("q_flg toggled to: %d\n" ,q_flg);
  718.       goto rch;
  719.      }
  720.      if    (q_flg)    goto rch;
  721.  
  722.      if    (c == '\'') {        /* toggle quote flag */
  723.       q1_flg = !q1_flg;
  724.       if(debug) printf("q1_flg toggled to: %d\n" ,q1_flg);
  725.       goto rch;
  726.      }
  727.      if    (q1_flg) goto rch;
  728.  
  729.     /*
  730.     Valid character    ... return to caller
  731.     */
  732.  
  733.      return (c);
  734. }/*rdchr.
  735. -----------------------------------------------*/
  736. fil_chr(f_buffer,f_eof)
  737.      FILE *f_buffer;
  738.      int *f_eof;
  739. {
  740.      int fc;
  741.      fc=getc(f_buffer);
  742.      if    (fc == CPMEOF || fc == EOF) {
  743.       *f_eof = TRUE;
  744.       fc = NUL0;
  745.      }
  746.      return(fc);
  747. }
  748. /*    CHECK THE    TOKEN  */                /*SRJ*/
  749.  
  750.  
  751. chk_token(c_token)
  752.      char    *c_token;
  753. {
  754.      char  u_token[MAX_LEN];
  755.      int   i;
  756.  
  757.      {
  758.       if (r_flg) return(TRUE);
  759.       i    = 0;
  760.       do { u_token[i] =    toupper(c_token[i]);
  761.       }    while (c_token[i++] != NUL0);
  762.  
  763.       switch(u_token[0]) {
  764.     case 'A': if (strcmp(u_token,"AUTO") ==    0) return(FALSE);
  765.           break;
  766.     case 'B': if (strcmp(u_token,"BREAK") == 0) return(FALSE);
  767.           break;
  768.     case 'C': if (strcmp(u_token,"CHAR") ==    0) return (FALSE);
  769.           if (strcmp(u_token,"CONTINUE") == 0) return (FALSE);
  770.           if (strcmp(u_token,"CASE") ==    0) return (FALSE);
  771.           break;
  772.  
  773.     case 'D': if(strcmp(u_token,"DOUBLE") == 0) return(FALSE);
  774.           if(strcmp(u_token,"DO") == 0)    return(FALSE);
  775.           if(strcmp(u_token,"DEFAULT") == 0) return(FALSE);
  776.           break;
  777.     case 'E': if(strcmp(u_token,"EXTERN") == 0) return(FALSE);
  778.           if(strcmp(u_token,"ELSE") == 0) return(FALSE);
  779.           if(strcmp(u_token,"ENTRY") ==    0) return(FALSE);
  780.           break;
  781.     case 'F': if(strcmp(u_token,"FLOAT") ==    0) return(FALSE);
  782.           if(strcmp(u_token,"FOR") == 0) return(FALSE);
  783.           break;
  784.     case 'G': if(strcmp(u_token,"GOTO") == 0) return(FALSE);
  785.           break;
  786.     case 'I': if(strcmp(u_token,"INT") == 0) return(FALSE);
  787.           if(strcmp(u_token,"IF") == 0)    return(FALSE);
  788.           break;
  789.     case 'L': if(strcmp(u_token,"LONG") == 0) return(FALSE);
  790.           break;
  791.     case 'R': if(strcmp(u_token,"RETURN") == 0) return(FALSE);
  792.           if(strcmp(u_token,"REGISTER")    == 0) return(FALSE);
  793.           break;
  794.     case 'S': if(strcmp(u_token,"STRUCT") == 0) return(FALSE);
  795.           if(strcmp(u_token,"SHORT") ==    0) return(FALSE);
  796.           if(strcmp(u_token,"STATIC") == 0) return(FALSE);
  797.           if(strcmp(u_token,"SIZEOF") == 0) return(FALSE);
  798.           if(strcmp(u_token,"SWITCH") == 0) return(FALSE);
  799.           break;
  800.     case 'T': if(strcmp(u_token,"TYPEDEF") == 0) return(FALSE);
  801.           break;
  802.     case 'U': if(strcmp(u_token,"UNION") ==    0) return(FALSE);
  803.           if(strcmp(u_token,"UNSIGNED")    == 0) return(FALSE);
  804.           break;
  805.     case 'W': if(strcmp(u_token,"WHILE") ==    0) return(FALSE);
  806.           break; }
  807.     }
  808.   return (TRUE);
  809. }/*chk_token.
  810. ---------------------------------------------*/
  811. /*    STORE THE    TOKEN  */                    /*SRJ*/
  812.  
  813.   /*
  814.    *    Install    parsed token and line reference    in linked structure
  815.    */
  816.  
  817. put_token(p_token,p_ref)
  818.      char *p_token;
  819.      int  p_ref;
  820. {
  821.      int  hsh_index;
  822.      int  i;
  823. /*   unsigned long j;    */                        /*SRJ*/
  824.      long int j;                    /*RSW*/
  825.      int  d;
  826.      int  found;
  827.      struct id_blk *idptr;
  828.      struct rf_blk *rfptr;
  829.      struct id_blk *alloc_id();
  830.      struct rf_blk *alloc_rf();
  831.      struct rf_blk *add_rf();
  832.  
  833.      if    (l_flg)    return;
  834.      j=0;
  835.      for (i=0; p_token[i] != NUL0; i++)     /* Hashing algorithm is far from */
  836.      j = j * 10 + p_token[i];     /* memory-bound index vector!      */
  837.  
  838.      hsh_index = j % MAX_WRD;                        /*SRJ*/
  839.  
  840.      if(debug) printf("hash index=%d ",hsh_index);
  841.  
  842.      found = FALSE;
  843.      d = 1;
  844.      do
  845.       {idptr = id_vector[hsh_index];
  846.       if (idptr == NUL0)
  847.            {id_cnt++;
  848.            idptr = id_vector[hsh_index] = alloc_id(p_token);
  849.            chain_alpha(idptr,p_token);
  850.            idptr->top_lnk =    idptr->lst_lnk = alloc_rf(p_ref);
  851.            found = TRUE;
  852.            if(debug) printf("empty cell in vector\n");
  853.            }
  854.         else
  855.            if (strcmp(p_token,idptr->id_name) == 0)
  856.            {idptr->lst_lnk = add_rf(idptr->lst_lnk,p_ref);
  857.            if(debug) printf("duplicate token\n");
  858.            found = TRUE;
  859.            }
  860.         else
  861.            {hsh_index += d;
  862.            if(debug) printf("hash clash  hash index=%d\n",hsh_index);
  863.            d +=    2;
  864.            rhsh_cnt++;
  865.            if (hsh_index >= MAX_WRD)
  866.              hsh_index -= MAX_WRD;
  867.            if (d == MAX_WRD)
  868.              {printf("\nERROR: Symbol table overflow\n");
  869.              exit(0);
  870.              }
  871.            }
  872.       }
  873.       while (!found);
  874.  
  875. return;
  876. }/*put_token.
  877. --------------------------------------------*/
  878. /*     BUILD THE CHAINS    */                    /*SRJ*/
  879.  
  880. chain_alpha(ca_ptr,ca_token)
  881.      struct id_blk *ca_ptr;
  882.      char  *ca_token;
  883. {
  884.      char  c;
  885.      int   f;
  886.      struct id_blk *cur_ptr;
  887.      struct id_blk *lst_ptr;
  888. /*** int isupper();   ****/           /** Microsoft C     macro **/
  889.  
  890.  
  891.      c = ca_token[0];
  892.      if    (c == '_')  c =    0;
  893.      else
  894.      /**  isupper(c) ? c=1+((c-'A')*2) : c=2+((c-'a')*2) ;     error or    not??
  895.       **  A good one for the puzzle book! Is the () required around (c=..)?
  896.       **  C86 and Microsoft C both req the ()'s, BDS C did not.
  897.       **  Is it    required because = has lower precedence    than ?:    ????
  898.       **/
  899.       isupper(c) ? (c=1+((c-'A')*2)) : (c=2+((c-'a')*2)) ;
  900.  
  901.      if(alpha_vector[c].alpha_top == NUL0)
  902.      {      alpha_vector[c].alpha_top =
  903.           alpha_vector[c].alpha_lst = ca_ptr;
  904.       ca_ptr->alpha_lnk = NUL0;
  905.       return;
  906.      }
  907.  
  908.     /*    check to see if    new id_blk should be inserted between
  909.      *    the alpha_vector header    block and the first id_blk in
  910.      *    the current alpha chain
  911.      */
  912.  
  913.      if(strcmp(alpha_vector[c].alpha_top->id_name,ca_token) >0)
  914.      {      ca_ptr->alpha_lnk=alpha_vector[c].alpha_top;
  915.       alpha_vector[c].alpha_top=ca_ptr;
  916.       return;
  917.      }
  918.  
  919.      if(strcmp(alpha_vector[c].alpha_lst->id_name,ca_token) < 0)
  920.      {      alpha_vector[c].alpha_lst->alpha_lnk = ca_ptr;
  921.       ca_ptr->alpha_lnk = NUL0;
  922.       alpha_vector[c].alpha_lst=ca_ptr;
  923.       return;
  924.      }
  925.  
  926.      cur_ptr = alpha_vector[c].alpha_top;
  927.      while(strcmp(cur_ptr->id_name,ca_token) < 0)
  928.      {      lst_ptr = cur_ptr;
  929.       cur_ptr = lst_ptr->alpha_lnk;
  930.      }
  931.  
  932.      lst_ptr->alpha_lnk    = ca_ptr;
  933.      ca_ptr->alpha_lnk = cur_ptr;
  934.      return;
  935. }/*chain_alpha.
  936. -----------------------------------------*/
  937. /*    GET MEMORY FOR TOKEN TREE    */                /*SRJ*/
  938.      struct id_blk
  939. *alloc_id(aid_token)
  940.      char  *aid_token;
  941. {
  942.      int  ai;
  943.      struct id_blk *aid_ptr;
  944.      char *malloc();                         /*    Microsoft C */
  945.  
  946. /*** if((aid_ptr =  alloc(sizeof(oneid))) == 0)    { ***/         /*    Microsoft C */
  947.      if((aid_ptr = (struct id_blk *) malloc(sizeof(oneid))) == 0) { /* MS C */
  948.  
  949.       printf("\nERROR: Unable to allocate identifier block\n");
  950.       exit(0);
  951.      }
  952.      ai=0;
  953.      do    {
  954.       aid_ptr->id_name[ai] = aid_token[ai];
  955.      } while (aid_token[ai++] != NUL0);
  956.      return (aid_ptr);
  957. }/*id_blk.
  958. -----------------------------------------*/
  959.  
  960.      struct rf_blk
  961. *alloc_rf(arf_ref)
  962.      int  arf_ref;
  963. {
  964.     int    ri;
  965.     struct rf_blk *arf_ptr;
  966.     char * malloc();                       /* Microsoft C */
  967.  
  968. /** if((arf_ptr    = alloc(sizeof(onerf)))    == 0) {    **/    /* Microsoft C */
  969.     if((arf_ptr    = (struct rf_blk *) malloc(sizeof(onerf))) == 0) { /* MS C */
  970.      printf("\nERROR: Unable to allocate reference block\n");
  971.      exit(0);
  972.     }
  973.     arf_ptr->ref_item[0] = arf_ref;
  974.     arf_ptr->ref_cnt = 1;
  975.     for    (ri=1;ri<MAX_REF;ri++)
  976.       arf_ptr->ref_item[ri]    = NUL0;
  977.     return (arf_ptr);
  978. }/*alloc_rf.
  979. ------------------------------------------*/
  980. /*    STORE REFERENCE IN TREE */                    /*SRJ*/
  981.  
  982.      struct rf_blk
  983. *add_rf(adr_ptr,adr_ref)
  984.  
  985.      struct rf_blk *adr_ptr;
  986.      int adr_ref;
  987. {
  988.      struct rf_blk *tmp_ptr;
  989.  
  990.      tmp_ptr = adr_ptr;
  991.      if(adr_ptr->ref_cnt == MAX_REF) {
  992.      /*** tmp_ptr = adr_ptr->ref_cnt = alloc_rf(adr_ref);    Microsoft C **/
  993.       adr_ptr->ref_cnt = alloc_rf(adr_ref);          /* Microsoft C **/
  994.       tmp_ptr = (struct rf_blk *) adr_ptr->ref_cnt;      /* Microsoft C **/
  995.      }
  996.      else
  997.      {      adr_ptr->ref_item[adr_ptr->ref_cnt++]    = adr_ref;
  998.      }
  999.      return (tmp_ptr);
  1000. }/*rf_blk.
  1001. ------------------------------------------*/
  1002. /*    PRINT THE    CROSS REFERENCE    TABLE */                /*SRJ*/
  1003.  
  1004. prnt_tbl()
  1005. {
  1006.      int prf_cnt;
  1007.      int pti;
  1008.      int pref;
  1009.      int lin_cnt;
  1010.      struct id_blk *pid_ptr;
  1011.      struct rf_blk *ptb_ptr;
  1012.  
  1013.      prt_ref = TRUE;
  1014.      prt_hdr();
  1015.      nl();
  1016.      for (pti=0;pti<MX_ALPHA;pti++)
  1017.       {if ((pid_ptr    = alpha_vector[pti].alpha_top) != NUL0)
  1018.            {do
  1019.             {fprintf(l_buffer,"%-14.13s: ",pid_ptr->id_name);/*WHR*/
  1020.             ptb_ptr=pid_ptr->top_lnk;
  1021.             lin_cnt=prf_cnt=0;
  1022.             do
  1023.              {if(prf_cnt ==    MAX_REF)
  1024.                   {prf_cnt=0;
  1025.              /*** ptb_ptr =    ptb_ptr->ref_cnt;  Microsoft C **/
  1026.                   ptb_ptr =    (struct    rf_blk *)ptb_ptr->ref_cnt;
  1027.                   }
  1028.              if(ptb_ptr > MAX_REF)
  1029.                  {if((pref=ptb_ptr->ref_item[prf_cnt++]) != 0)
  1030.                       {fprintf(l_buffer,"%-4d  ",pref); /*WHR*/
  1031.                       if (++lin_cnt    == REFS_LIN )
  1032.                         {nl();
  1033.                         fprintf(l_buffer,"%16s",": ");
  1034.                         lin_cnt=0;
  1035.                         }
  1036.                       }
  1037.                  }
  1038.                  else
  1039.                        pref=0;
  1040.              }
  1041.             while (pref);
  1042.             nl();
  1043.             }
  1044.            while ((pid_ptr=pid_ptr->alpha_lnk) != NUL0);
  1045.            }
  1046.       }
  1047. }/*prnt_tbl.
  1048. ---------------------------------------*/
  1049. /*    TOP OF PAGE AND PRINT THE    HEADER */            /*SRJ*/
  1050.  
  1051. prt_hdr()
  1052.  
  1053. {fprintf(l_buffer,
  1054.   "\r\f%-10s [file d/t= %d/%02d/%02d  %d:%02d]   [clock d/t= %d %s %d  %d:%02d:%02d]   Page %d\n\n",
  1055.     gbl_fil,file_mo,file_d,file_y,file_h,file_mi,
  1056.     d,months[mo],y,h,mi,s,++pagno);        /*SRJ*/
  1057.  
  1058. paglin =3;
  1059. return;
  1060. }
  1061. /*   NEW LINE */                            /*SRJ*/
  1062.  
  1063. nl()
  1064.  
  1065. {fputc('\n',l_buffer);    /* output cr/lf    */            /*SRJ*/
  1066.  
  1067. if (++paglin >=    LINE_PAG )
  1068.     prt_hdr();
  1069. if(!prt_ref)
  1070.     {fprintf(l_buffer,"%4d ",++linum);        /*SRJ*/
  1071.     if(i_flg)                /*SRJ*/
  1072.         fprintf(l_buffer," %4d: ",++edtnum);    /*SRJ*//*WHR*/
  1073.     }
  1074. /* print the status on the console */
  1075. if(o_flg)
  1076.     if(linum % 60 == 1)
  1077.         printf("\n<%d>\t",linum);
  1078.       else
  1079.         printf(".");
  1080. return;
  1081. }/*nl.
  1082. -------------------------------------------*/
  1083. /*=============    end of file xc.c ==========================*/
  1084.